/*******************************************************************************
 * CLI - A simple command line interface.
 * Copyright (C) 2016-2021 Daniele Pallastrelli
 *
 * Boost Software License - Version 1.0 - August 17th, 2003
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ******************************************************************************/

#include <boost/test/unit_test.hpp>
#include "cli/detail/split.h"

using namespace std;
using namespace cli;
using namespace cli::detail;

using VS = vector<string>;

BOOST_AUTO_TEST_SUITE(SplitSuite)

BOOST_AUTO_TEST_CASE(OddCases)
{
    VS strs;

    split(strs, ""); // empty
    BOOST_CHECK_EQUAL(strs.size(), 0);

    split(strs, " "); // one space
    BOOST_CHECK_EQUAL(strs.size(), 0);

    split(strs, "  "); // two spaces
    BOOST_CHECK_EQUAL(strs.size(), 0);

    split(strs, "   "); // three spaces
    BOOST_CHECK_EQUAL(strs.size(), 0);

    split(strs, "\t"); // one tab
    BOOST_CHECK_EQUAL(strs.size(), 0);

    split(strs, "\t\t"); // two tabs
    BOOST_CHECK_EQUAL(strs.size(), 0);

    split(strs, " \t \t      "); // tabs and spaces
    BOOST_CHECK_EQUAL(strs.size(), 0);
}

BOOST_AUTO_TEST_CASE(StandardCases)
{
    VS strs;

    split(strs, "1234567890"); // one word
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], "1234567890");

    split(strs, "  foo "); // one word with spaces
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], "foo");

    split(strs, "  foo \t \t bar \t"); // two words with spaces
    BOOST_CHECK_EQUAL(strs.size(), 2);
    BOOST_CHECK_EQUAL(strs[0], "foo");
    BOOST_CHECK_EQUAL(strs[1], "bar");
}

BOOST_AUTO_TEST_CASE(DoubleQuotedCases)
{
    VS strs;

    split(strs, "\"\""); // nothing
    BOOST_CHECK_EQUAL(strs.size(), 0);

    split(strs, "\"foo bar\""); // two words
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], "foo bar");

    split(strs, "    \t\t \"foo \tbar\"     \t"); // two words with spaces
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], "foo \tbar");

    split(strs, " first   \t\t \"foo \tbar\"     \t last"); // mixed
    BOOST_CHECK_EQUAL(strs.size(), 3);
    BOOST_CHECK_EQUAL(strs[0], "first");
    BOOST_CHECK_EQUAL(strs[1], "foo \tbar");
    BOOST_CHECK_EQUAL(strs[2], "last");

    split(strs, "first\"foo \tbar\"");
    BOOST_CHECK_EQUAL(strs.size(), 2);
    BOOST_CHECK_EQUAL(strs[0], "first");
    BOOST_CHECK_EQUAL(strs[1], "foo \tbar");

    split(strs, "first \"'second' 'thirdh'\""); // input: first "'second' 'thirdh'"
    BOOST_CHECK_EQUAL(strs.size(), 2);
    BOOST_CHECK_EQUAL(strs[0], "first");
    BOOST_CHECK_EQUAL(strs[1], "'second' 'thirdh'");
}

BOOST_AUTO_TEST_CASE(SingleQuotedCases)
{
    VS strs;

    split(strs, "''"); // nothing
    BOOST_CHECK_EQUAL(strs.size(), 0);

    split(strs, "'foo bar'"); // two words
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], "foo bar");

    split(strs, "    \t\t 'foo \tbar'     \t"); // two words with spaces
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], "foo \tbar");

    split(strs, " first   \t\t 'foo \tbar'     \t last"); // mixed
    BOOST_CHECK_EQUAL(strs.size(), 3);
    BOOST_CHECK_EQUAL(strs[0], "first");
    BOOST_CHECK_EQUAL(strs[1], "foo \tbar");
    BOOST_CHECK_EQUAL(strs[2], "last");

    split(strs, "first'foo \tbar'"); // first'foo \tbar'
    BOOST_CHECK_EQUAL(strs.size(), 2);
    BOOST_CHECK_EQUAL(strs[0], "first");
    BOOST_CHECK_EQUAL(strs[1], "foo \tbar");

    split(strs, R"(first '"second" "thirdh"')"); // first '"second" "thirdh"'
    BOOST_CHECK_EQUAL(strs.size(), 2);
    BOOST_CHECK_EQUAL(strs[0], "first");
    BOOST_CHECK_EQUAL(strs[1], "\"second\" \"thirdh\"");
}

/*
    foo \"bar
        foo
        "bar

    foo \'bar\'
        foo
        'bar'

    foo bar f\"oo
        foo
        bar
        f"oo

    "foo\"bar\'foo"
        foo"bar'foo

    'foo\'bar\"foo'
        foo'bar"foo

    "foo\bar"
        foo\bar

    "foo\\\"bar"
        foo\"bar
*/
BOOST_AUTO_TEST_CASE(EscapedCases)
{
    VS strs;

/*
    foo \"bar
        foo
        "bar
*/
    split(strs, R"(foo \"bar)");
    BOOST_CHECK_EQUAL(strs.size(), 2);
    BOOST_CHECK_EQUAL(strs[0], "foo");
    BOOST_CHECK_EQUAL(strs[1], R"("bar)");

/*
    foo \'bar\'
        foo
        'bar'
*/
    split(strs, R"(foo \'bar\')");
    BOOST_CHECK_EQUAL(strs.size(), 2);
    BOOST_CHECK_EQUAL(strs[0], "foo");
    BOOST_CHECK_EQUAL(strs[1], R"('bar')");

/*
    foo bar f\"oo
        foo
        bar
        f"oo
*/
    split(strs, R"(foo bar f\"oo)");
    BOOST_CHECK_EQUAL(strs.size(), 3);
    BOOST_CHECK_EQUAL(strs[0], "foo");
    BOOST_CHECK_EQUAL(strs[1], "bar");
    BOOST_CHECK_EQUAL(strs[2], R"(f"oo)");

/*
    "foo\"bar\'foo"
        foo"bar'foo
*/
    split(strs, R"("foo\"bar\'foo")");
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], R"(foo"bar'foo)");

/*
    'foo\'bar\"foo'
        foo'bar"foo
*/
    split(strs, R"('foo\'bar\"foo')");
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], R"(foo'bar"foo)");

/*
    "foo\bar"
        foo\bar
*/
    split(strs, R"("foo\bar")");
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], R"(foo\bar)");

/*
    "foo\\\"bar"
        foo\"bar
*/
    split(strs, R"("foo\\\"bar")");
    BOOST_CHECK_EQUAL(strs.size(), 1);
    BOOST_CHECK_EQUAL(strs[0], R"(foo\"bar)");
}

BOOST_AUTO_TEST_CASE(Symbols)
{
    VS strs;

    split(strs, "!foo"); // two words!
    BOOST_CHECK_EQUAL(strs.size(), 2);
    BOOST_CHECK_EQUAL(strs[0], "!");
    BOOST_CHECK_EQUAL(strs[1], "foo");

    split(strs, "    !    foo    "); // two words
    BOOST_CHECK_EQUAL(strs.size(), 2);
    BOOST_CHECK_EQUAL(strs[0], "!");
    BOOST_CHECK_EQUAL(strs[1], "foo");

    split(strs, "!42!69!"); // 5 words
    BOOST_CHECK_EQUAL(strs.size(), 5);
    BOOST_CHECK_EQUAL(strs[0], "!");
    BOOST_CHECK_EQUAL(strs[1], "42");
    BOOST_CHECK_EQUAL(strs[2], "!");
    BOOST_CHECK_EQUAL(strs[3], "69");
    BOOST_CHECK_EQUAL(strs[4], "!");

    split(strs, " 38!42!69! 72 ! 33"); // 9 words
    BOOST_CHECK_EQUAL(strs.size(), 9);
    BOOST_CHECK_EQUAL(strs[0], "38");
    BOOST_CHECK_EQUAL(strs[1], "!");
    BOOST_CHECK_EQUAL(strs[2], "42");
    BOOST_CHECK_EQUAL(strs[3], "!");
    BOOST_CHECK_EQUAL(strs[4], "69");
    BOOST_CHECK_EQUAL(strs[5], "!");
    BOOST_CHECK_EQUAL(strs[6], "72");
    BOOST_CHECK_EQUAL(strs[7], "!");
    BOOST_CHECK_EQUAL(strs[8], "33");

    split(strs, R"( 38!"42!69"! "72 ! 33" )"); // 5 words
    BOOST_CHECK_EQUAL(strs.size(), 5);
    BOOST_CHECK_EQUAL(strs[0], "38");
    BOOST_CHECK_EQUAL(strs[1], "!");
    BOOST_CHECK_EQUAL(strs[2], "42!69");
    BOOST_CHECK_EQUAL(strs[3], "!");
    BOOST_CHECK_EQUAL(strs[4], "72 ! 33");
}

BOOST_AUTO_TEST_SUITE_END()